package com.aiwhose.aiwhosecore.bean;

import lombok.Data;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 接口公共响应对象
 *
 * @author fay
 * @date 2022-01-24
 */
@Data
public class Result<T, E> {

    private static final long serialVersionUID = 1L;

    /**
     * 请求成功标识
     */
    private boolean success = true;

    /**
     * 响应码
     */
    private Integer code = OK_200;

    /**
     * 响应消息
     */
    private String message = OK_MSG;

    /**
     * 响应对象
     */
    private T data;

    /**
     * 响应列表
     */
    private Collection<T> dataList;

    /**
     * 响应扩展
     */
    private E extend;

    /**
     * 时间戳
     */
    private long timestamp = System.currentTimeMillis();

    /**
     * 默认响应码：200成功，500失败，401无权限
     */
    public static final int OK_200 = 200;
    public static final int ERROR_500 = 500;
    public static final int NO_AUTH_401 = 401;

    /**
     * 默认响应消息
     */
    public static final String OK_MSG = "成功";
    public static final String ERROR_MSG = "失败";
    public static final String NO_AUTH_MSG = "无权限";

    // 创建自定义的日期时间格式
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

    /**
     * 创建通用响应Map的方法
     */
    private static <T, E> Map<String, Object> createResponse(boolean success, Integer code, String message, T data, Collection<T> dataList, E extend) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("success", success);
        map.put("code", code);
        map.put("message", message);
        map.put("data", data);
        map.put("dataList", dataList);
        map.put("extend", extend);
        map.put("time", getCurrentFormattedTime());
        return map;
    }

    /**
     * 获取当前时间戳的格式化字符串
     */
    private static String getCurrentFormattedTime() {
        return LocalDateTime.now().format(FORMATTER);
    }

    /**
     * 静态方法：成功响应
     */
    public static <T, E> Result<T, E> ok() {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(OK_MSG);
    }

    public static <T, E> Result<T, E> ok(String message) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(message);
    }

    public static <T, E> Result<T, E> ok(T data) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(OK_MSG).setData(data);
    }

    public static <T, E> Result<T, E> ok(T data, String message) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(message).setData(data);
    }

    public static <T, E> Result<T, E> ok(T data, String message, Integer code) {
        return new Result<T, E>().setSuccess(true).setCode(code).setMessage(message).setData(data);
    }

    public static <T, E> Result<T, E> ok(List<T> dataList) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(OK_MSG).setDataList(dataList);
    }

    public static <T, E> Result<T, E> ok(List<T> dataList, String message) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(message).setDataList(dataList);
    }

    public static <T, E> Result<T, E> ok(T data, E extend) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(OK_MSG).setData(data).setExtend(extend);
    }

    public static <T, E> Result<T, E> ok(List<T> dataList, E extend) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(OK_MSG).setDataList(dataList).setExtend(extend);
    }

    public static <T, E> Result<T, E> ok(T data, List<T> dataList, E extend) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(OK_MSG).setData(data).setDataList(dataList).setExtend(extend);
    }

    public static <T, E> Result<T, E> ok(T data, List<T> dataList, E extend, String message) {
        return new Result<T, E>().setSuccess(true).setCode(OK_200).setMessage(message).setData(data).setDataList(dataList).setExtend(extend);
    }

    public static <T, E> Result<T, E> ok(T data, List<T> dataList, E extend, String message, Integer code) {
        return new Result<T, E>().setSuccess(true).setCode(code).setMessage(message).setData(data).setDataList(dataList).setExtend(extend);
    }

    /**
     * 静态方法：失败响应
     */
    public static <T, E> Result<T, E> error() {
        return new Result<T, E>().setSuccess(false).setCode(ERROR_500).setMessage(ERROR_MSG);
    }

    public static <T, E> Result<T, E> error(String message) {
        return new Result<T, E>().setSuccess(false).setCode(ERROR_500).setMessage(message);
    }

    public static <T, E> Result<T, E> error(Integer code, String message) {
        return new Result<T, E>().setSuccess(false).setCode(code).setMessage(message);
    }

    public static <T, E> Result<T, E> error(String message, T data) {
        return new Result<T, E>().setSuccess(false).setCode(ERROR_500).setMessage(message).setData(data);
    }

    /**
     * 静态方法：无权访问响应
     */
    public static <T, E> Result<T, E> noAuth() {
        return new Result<T, E>().setSuccess(false).setCode(NO_AUTH_401).setMessage(NO_AUTH_MSG);
    }

    public static <T, E> Result<T, E> noAuth(String message) {
        return new Result<T, E>().setSuccess(false).setCode(NO_AUTH_401).setMessage(message);
    }

    /**
     * 链式调用的Setter方法
     */
    public Result<T, E> setSuccess(boolean success) {
        this.success = success;
        return this;
    }

    public Result<T, E> setCode(Integer code) {
        this.code = code;
        return this;
    }

    public Result<T, E> setMessage(String message) {
        this.message = message;
        return this;
    }

    public Result<T, E> setData(T data) {
        this.data = data;
        return this;
    }

    public Result<T, E> setDataList(Collection<T> dataList) {
        this.dataList = dataList;
        return this;
    }

    public Result<T, E> setExtend(E extend) {
        this.extend = extend;
        return this;
    }

    public Result<T, E> setTimestamp(long timestamp) {
        this.timestamp = timestamp;
        return this;
    }
}
